package com.kaibes.web.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;

@Configuration
@WebFilter
public class FilterInternalImpl extends OncePerRequestFilter implements InitializingBean {

    @Autowired
    private FilterInternalConfig config;
    @Autowired(required = false)
    private List<BeforeFilterInternal> beforeFilterInternalList;
    @Autowired(required = false)
    private List<DoFilterInternal> doFilterInternalList;
    
    private static String MESSAGE = "x-api-message";
    
    private static String urlEncode(String message) {
        try {
            return URLEncoder.encode(message, "utf-8");
        } catch (UnsupportedEncodingException e) {
            return message;
        }
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
    	
        if (request.getMethod().equals("GET")) {
            String uri = request.getRequestURI();
            for (String string : config.getResourcesWhiteList()) {
                if (uri.toLowerCase().endsWith(string)) {
                    filterChain.doFilter(request, response);
                    return;
                }
            }
            
            for (String string : config.getPathWhiteStartList()) {
                if (uri.startsWith(string)) {
                    filterChain.doFilter(request, response);
                    return;
                }
            }
            
            for (String string : config.getPathWhiteList()) {
                if (uri.equals(string)) {
                    filterChain.doFilter(request, response);
                    return;
                }
            }
        }
        
        if (beforeFilterInternalList != null) {
        	for (BeforeFilterInternal beforeFilterInternal : beforeFilterInternalList) {
        		if (beforeFilterInternal.beforeFilterInternal(request, response)) {
        			if (!response.isCommitted()) {
        				response.sendError(404);
        			}
        			return;
        		}
        	}
        }
        FilterInternal filterInternal = new FilterInternal(request, response);
        try {
        	if (doFilterInternalList != null) {
                for (DoFilterInternal doFilter : doFilterInternalList) {
                    doFilter.doFilterInternal(filterInternal);
                    if (filterInternal.isEnd()) {
                        break;
                    }
                }
            }
		} catch (RequestFilterException e) {
			response.setHeader(MESSAGE, urlEncode(e.getMessage()));
			filterInternal.setBroken(true);
		}
        
        if (filterInternal.isBroken()) {
            response.sendError(HttpStatus.BAD_REQUEST.value());
            return;
        }
        
        filterChain.doFilter(filterInternal.getRequest(), filterInternal.getResponse());
        
    }
    
    @Override
    public void afterPropertiesSet() throws ServletException {
    	if (beforeFilterInternalList != null) {
            Collections.sort(beforeFilterInternalList, (o1, o2)->Integer.compare(o1.order(), o2.order()));
        }
        if (doFilterInternalList != null) {
            Collections.sort(doFilterInternalList, (o1, o2)->Integer.compare(o1.order(), o2.order()));
        }
    }
}
